﻿
using LightCAD.Three;

namespace QdArch
{
    public class WallAttribute : CptAttribute
    {
        public WallAttribute(string category, string subCategorys) : base(category, subCategorys)
        {

        }
        static WallAttribute()
        {
            CptTypeParamsDef<QdWallDef>.ParamsDef = new ParameterSetDefinition { new ParameterDefinition { DataType = LcDataType.String, Name = "MaterialUuid", DisplayName = "材质" } };
        }
        public const string CommonWallUuid = "8A5C1F17-5C33-78A6-9C26-52EA59E34C4A";
        public const string MasonryWallUuid = "0ABEAC6B-A57F-FACA-E151-C2853398D7E1";
        public const string ConcreteWallUuid = "300F803B-CDDD-C2D2-91E7-3DD82629CE51";
        public override LcComponentDefinition GetBuiltinCpt(string subCategory)
        {
            var typeParams = new LcParameterSet(CptTypeParamsDef<QdWallDef>.ParamsDef);
            switch (subCategory) 
            {
                case "常规墙":
                    //常规墙上的材质无意义
                    return new QdWallDef(CommonWallUuid, "内置", subCategory, typeParams);
                case "砌体墙":
                    typeParams["MaterialUuid"] = MaterialManager.MasonryUuid;
                    return new QdWallDef(MasonryWallUuid,"内置", subCategory, typeParams);
                case "混凝土墙":
                    typeParams["MaterialUuid"] = MaterialManager.ConcreteUuid;
                    return new QdWallDef(ConcreteWallUuid, "内置", subCategory, typeParams);
            }
            return null;
        }
    }
    [WallAttribute("墙","常规墙,砌体墙,混凝土墙")]
    public class QdWallDef : LcComponentDefinition 
    {
        public QdWallDef(string uuid,string name,string subCategory,LcParameterSet typeParams) :base(uuid,name,"墙",subCategory, typeParams)
        {
            this.Parameters = new ParameterSetDefinition 
            {
                new ParameterDefinition(){ Name = "Width",DisplayName="墙宽", DataType=LcDataType.Double },
                new ParameterDefinition(){ Name = "Height",DisplayName="墙高", DataType=LcDataType.Double },
                new ParameterDefinition(){ Name = "Bottom",DisplayName="底高度", DataType=LcDataType.Double },
                new ParameterDefinition(){ Name = "CenterOffset",DisplayName="偏移",DataType= LcDataType.Double},
                new ParameterDefinition(){ Name = "IsReverse",DisplayName="翻转",DataType= LcDataType.Bool}
            };
            var mat = MaterialManager.DefaultMat;
            if (SubCategory == "常规墙")
            {
                this.Parameters.Add(new ParameterDefinition { Name = "MaterialUuid", DisplayName = "材质", DataType = LcDataType.String, DefaultValue = MaterialManager.MasonryUuid });
                this.Solid3dProvider = new Solid3dProvider(name)
                {
                    AssignMaterialsFunc = (c, s) =>
                     new LcMaterial[] { MaterialManager.GetMaterial(c.Parameters.GetValue<string>("MaterialUuid")) }
                };
                return;
            }
            else
            {
                if (subCategory == "砌体墙")
                    mat = MaterialManager.GetMaterial(MaterialManager.MasonryUuid);
                else if (subCategory == "混凝土墙")
                    mat = MaterialManager.GetMaterial(MaterialManager.ConcreteUuid);
                this.Solid3dProvider = new Solid3dProvider(name) { AssignMaterialsFunc = (c, s) => new LcMaterial[] { mat } };
            }
        }
    }
    public class QdWall : DirectComponent
    {
        public Line2d BaseLine
        {
            get
            {

                return (Line2d)this.BaseCurve;
            }
            set
            {
                value.Source = this;
                this.Curves[0].Curve2ds.Clear();
                this.Curves[0].Curve2ds.Add(value);
            }
        }
        //TODO 关于默认值 需要在创建时指定，因为需要根据环境給值
        //public double Width { get; set; }
        //public double Height { get; set; }
        //public double Bottom { get; set; }
        //public double CenterOffset { get; set; }
        //public bool IsReverse { get; set; }
        public override Curve2dGroupCollection Curves { get; set; } = new Curve2dGroupCollection() { new Curve2dGroup() { Curve2ds=new ListEx<Curve2d>()} };

        public double Width
        {
            get
            {
                return Convert.ToDouble(this.Parameters["Width"]);
            }
            set
            {
                this.Parameters["Width"] = value;
            }
        }
        public double Height
        {
            get
            {
                return Convert.ToDouble(this.Parameters["Height"]);
            }
            set
            {
                this.Parameters["Height"] = value;
            }
        }
        public double Bottom
        {
            get
            {
                return Convert.ToDouble(this.Parameters["Bottom"]);
            }
            set
            {
                this.Parameters["Bottom"] = value;
            }
        }

        public double CenterOffset
        {
            get
            {
                return Convert.ToDouble(this.Parameters["CenterOffset"]);
            }
            set
            {
                this.Parameters["CenterOffset"] = value;
            }
        }
        public bool IsReverse
        {
            get
            {
                return Convert.ToBoolean(this.Parameters["IsReverse"]);
            }
            set
            {
                this.Parameters["IsReverse"] = value;
            }
        }
        public QdWall(QdWallDef wallDef):base(wallDef)
        {
            this.Type = ArchElementType.Wall;
        }
        public static List<Line2d> GetShapeCurves(Line2d line, double width)
        {

            double x1 = line.Start.X;
            double y1 = line.Start.Y;
            double x2 = line.End.X;
            double y2 = line.End.Y;
            double setoff = (width) / 2;
            Vector2 p1=new Vector2();
            Vector2 p2=new Vector2();
            Vector2 p3=new Vector2();
            Vector2 p4=new Vector2();

            if (x1 == x2)
            {
                p1.Y = y1;
                p1.X = x1 + setoff;
                p2.Y = y1;
                p2.X = x1 - setoff;
                p3.Y = y2;
                p3.X = x2 - setoff;
                p4.Y = y2;
                p4.X = x2 + setoff;
            }
            else
            if (y1 == y2)
            {
                p1.Y = y1 + setoff;
                p1.X = x1;
                p2.Y = y1 - setoff;
                p2.X = x1;
                p3.Y = y2 - setoff;
                p3.X = x2;
                p4.Y = y2 + setoff;
                p4.X = x2;
            }
            else
            {
                double k = (y2 - y1) / (x2 - x1);
                double k1 = -1 / k;
                double b1 = y1 - k1 * x1;



                double xA = x1;
                double yA = y1;
                double xB = x1 + Math.Pow(width, 2);
                double yB = k1 * xB + b1;

                // 给定距离
                double distance = setoff;

                // 计算线段的方向向量
                double directionX = xB - xA;
                double directionY = yB - yA;

                // 计算方向向量的模长
                double length = Math.Sqrt(directionX * directionX + directionY * directionY);

                // 标准化方向向量（单位化）
                double unitDirectionX = directionX / length;
                double unitDirectionY = directionY / length;

                // 计算目标点的坐标
                p1.X = xA + distance * unitDirectionX;
                p1.Y = yA + distance * unitDirectionY;


                Matrix3 matrix3 = Matrix3.GetMove(p1, line.Start);
                p2 = matrix3.MultiplyPoint(line.Start);

                matrix3 = Matrix3.GetMove(line.Start, line.End);

                p3 = matrix3.MultiplyPoint(p2);
                p4 = matrix3.MultiplyPoint(p1);
 

            }

            List<Line2d> line2Ds = new List<Line2d>();
            Line2d line2D = new Line2d();
            line2D.Start = p1;
            line2D.End = p2;

            line2Ds.Add(line2D);
            line2D = new Line2d();
            line2D.Start = p2;
            line2D.End = p3;

            line2Ds.Add(line2D);
            line2D = new Line2d();
            line2D.Start = p3;
            line2D.End = p4;

            line2Ds.Add(line2D);
            line2D = new Line2d();
            line2D.Start = p4;
            line2D.End = p1;

            line2Ds.Add(line2D);
            return line2Ds;
        }
        public void set()
        {
            //var args = new PropertyChangedEventArgs
            //{
            //    Object = this,
            //    PropertyName = "",
            //    OldValue = null,
            //    NewValue = null,
            //};
            //this.PropertyChangedAfter(args);
            //this.PropertyChangedAfter?.Invoke(this, args);
            //this.docRt.Document.OnPropertyChangedAfter(args);
            ////RestWalls(qdWall);
        }
        public void CreateShapeCurves()
        {
            this.Points.Clear();
            this.Curves.Clear();
            List<Line2d> line2Ds = GetShapeCurves(this.BaseLine, this.Width);
            this.Points.Add(line2Ds[1].Start);
            this.Points.Add(line2Ds[1].End);
            this.Points.Add(line2Ds[3].Start);
            this.Points.Add(line2Ds[3].End);
            Curve2dGroup crGrp = null;
            if (this.Curves.Count == 0)
            {
                this.Curves.Add(new Curve2dGroup { Curve2ds = new ListEx<Curve2d>() });
            }
            crGrp = this.Curves[0];
            crGrp.Curve2ds.AddRange(line2Ds.Cast<Curve2d>());
        }
        public  void ResetShapeCurves()
        {
            CreateShapeCurves();
            //List<Line2d> line2Ds =
            //GetShapeCurves(this.BaseLine, this.Width);
            //this.Points.Add(line2Ds[1].Start);
            //this.Points.Add(line2Ds[1].End);
            //this.Points.Add(line2Ds[3].Start);
            //this.Points.Add(line2Ds[3].End);
            //this.Curves.AddRange(line2Ds);



        }
        public void AddLcComponent(LcElement lcElement, string name, AssociateType type)
        {
            AssociateElement associateElement = new AssociateElement();

            associateElement.Tag = lcElement.Id; //将原始的LcElement.Id存下来，方便Remove时来匹配
            associateElement.Type = type;
            associateElement.Name = name;
            this.AssociateElements.Add(associateElement);
            if (name == nameof(QdDoorInstance))
            {
                QdDoorInstance door = (QdDoorInstance)lcElement;

                associateElement.Element = new QdDoorInstance(door.DoorDef);
                associateElement.Element.Initilize(door.Document);
                associateElement.Element.Copy(door); //Clone后Id会发生改变

                Vector2 s1 = Line2d.GetFootofperpendicular(door.StartPoint, this.Points[0], this.Points[1]);
                Vector2 e1 = Line2d.GetFootofperpendicular(door.StartPoint, this.Points[2], this.Points[3]);
                Vector2 s2 = Line2d.GetFootofperpendicular(door.EndPoint, this.Points[0], this.Points[1]);
                Vector2 e2 = Line2d.GetFootofperpendicular(door.EndPoint, this.Points[2], this.Points[3]);

                Line2d line1 = new Line2d { Start = s1, End = e1 };
                Line2d line2 = new Line2d { Start = s2, End = e2 };
                Dictionary<Line2d, List<Line2d>> dls = new Dictionary<Line2d, List<Line2d>>();
                foreach (Line2d item in this.Curves[0].Curve2ds)
                {

                    if (Line2d.PointInLine(item, s1) && Line2d.PointInLine(item, s2))
                    {
                        dls.Add(item, Line2d.BreakLineBy2line(item, line1, line2));

                    }
                    if (Line2d.PointInLine(item, e1) && Line2d.PointInLine(item, e2))
                    {
                        dls.Add(item, Line2d.BreakLineBy2line(item, line1, line2));

                    }
                }
                foreach (var item in dls)
                {
                    this.Curves[0].Curve2ds.Remove(item.Key); this.Curves[0].Curve2ds.AddRange(item.Value);
                }
                this.Curves[0].Curve2ds.Add(line1); this.Curves[0].Curve2ds.Add(line2);
            }

            if (name == nameof(QdWindowInstance))
            {
                QdWindowInstance window = (QdWindowInstance)lcElement;

                associateElement.Element = new QdWindowInstance(window.WindowDef);
                associateElement.Element.Initilize(window.Document);
                associateElement.Element.Copy(window); //Clone后Id会发生改变
                Vector2 s1 = Line2d.GetFootofperpendicular(window.StartPoint, this.Points[0], this.Points[1]);
                Vector2 e1 = Line2d.GetFootofperpendicular(window.StartPoint, this.Points[2], this.Points[3]);
                Vector2 s2 = Line2d.GetFootofperpendicular(window.EndPoint, this.Points[0], this.Points[1]);
                Vector2 e2 = Line2d.GetFootofperpendicular(window.EndPoint, this.Points[2], this.Points[3]);

                Line2d line1 = new Line2d { Start = s1, End = e1 };
                Line2d line2 = new Line2d { Start = s2, End = e2 };
                Dictionary<Line2d, List<Line2d>> dls = new Dictionary<Line2d, List<Line2d>>();
                foreach (Line2d item in this.Curves[0].Curve2ds)
                {

                    if (Line2d.PointInLine(item, s1) && Line2d.PointInLine(item, s2))
                    {
                        dls.Add(item, Line2d.BreakLineBy2line(item, line1, line2));

                    }
                    if (Line2d.PointInLine(item, e1) && Line2d.PointInLine(item, e2))
                    {
                        dls.Add(item, Line2d.BreakLineBy2line(item, line1, line2));

                    }
                }
                foreach (var item in dls)
                {
                    this.Curves[0].Curve2ds.Remove(item.Key); this.Curves[0].Curve2ds.AddRange(item.Value);
                }
                this.Curves[0].Curve2ds.Add(line1); this.Curves[0].Curve2ds.Add(line2);
            }

        }
        public void RemoveLcComponent(LcElement lcElement, string name, AssociateType type)
        {
          
            AssociateElement associateElement = this.AssociateElements.Find(e => (long)e.Tag == lcElement.Id);

            if (associateElement == null)
                return;

            if (name == nameof(QdDoorInstance))
            {
                QdDoorInstance door = (QdDoorInstance)associateElement.Element;
                Vector2 s1 = Line2d.GetFootofperpendicular(door.StartPoint, this.Points[0], this.Points[1]);
                Vector2 e1 = Line2d.GetFootofperpendicular(door.StartPoint, this.Points[2], this.Points[3]);
                Vector2 s2 = Line2d.GetFootofperpendicular(door.EndPoint, this.Points[0], this.Points[1]);
                Vector2 e2 = Line2d.GetFootofperpendicular(door.EndPoint, this.Points[2], this.Points[3]);

                Line2d line1 = new Line2d { Start = s1, End = e1 };
                Line2d line2 = new Line2d { Start = s2, End = e2 };

                List<Line2d> rs = new List<Line2d>();
                foreach (Line2d item in this.Curves[0].Curve2ds)
                {

                    if (Line2d.PointInLine(item, door.StartPoint))
                    {
                        rs.Add(item);
                    }
                    if (Line2d.PointInLine(item, door.EndPoint))
                    {
                        rs.Add(item);

                    }
                }
                foreach (var item in rs)
                {
                    this.Curves[0].Curve2ds.Remove(item);
                }
                rs = new List<Line2d>();
                foreach (Line2d item in this.Curves[0].Curve2ds)
                {
                    if (Line2d.PointInLine(item, s1) || Line2d.PointInLine(item, s2) || Line2d.PointInLine(item, e1) || Line2d.PointInLine(item, e2))
                    {
                        rs.Add(item);
                    }
                }
                Dictionary<Line2d, Line2d> dls = new Dictionary<Line2d, Line2d>();
                List<Line2d> cus = new List<Line2d>();
                foreach (Line2d item in rs)
                {
                    foreach (Line2d item2 in rs)
                    {
                        if (item != item2 && Line2d.LineInLine1(item, item2))
                        {
                            if (!cus.Contains(item2) && !cus.Contains(item))
                            {
                                cus.Add(item2); cus.Add(item);
                                dls.Add(item, item2);
                            }
                        }
                    }
                }
                foreach (var item in dls)
                {
                    this.Curves[0].Curve2ds.Remove(item.Key);
                    this.Curves[0].Curve2ds.Remove(item.Value);
                    if (Vector2.Distance(item.Key.Start, item.Value.Start) > Vector2.Distance(item.Key.End, item.Value.Start))
                    {
                        if (Vector2.Distance(item.Key.Start, item.Value.End) > Vector2.Distance(item.Key.Start, item.Value.Start))
                            this.Curves[0].Curve2ds.Add(new Line2d() { Start = item.Key.Start, End = item.Value.End });
                        else
                            this.Curves[0].Curve2ds.Add(new Line2d() { Start = item.Key.Start, End = item.Value.Start });

                    }
                    else
                    {
                        if (Vector2.Distance(item.Key.Start, item.Value.End) > Vector2.Distance(item.Key.Start, item.Value.Start))
                            this.Curves[0].Curve2ds.Add(new Line2d() { Start = item.Key.End, End = item.Value.End });
                        else
                            this.Curves[0].Curve2ds.Add(new Line2d() { Start = item.Key.End, End = item.Value.Start });
                    }
                }

            }

            if (name == nameof(QdWindowInstance))
            {
                QdWindowInstance window = (QdWindowInstance)associateElement.Element;
                Vector2 s1 = Line2d.GetFootofperpendicular(window.StartPoint, this.Points[0], this.Points[1]);
                Vector2 e1 = Line2d.GetFootofperpendicular(window.StartPoint, this.Points[2], this.Points[3]);
                Vector2 s2 = Line2d.GetFootofperpendicular(window.EndPoint, this.Points[0], this.Points[1]);
                Vector2 e2 = Line2d.GetFootofperpendicular(window.EndPoint, this.Points[2], this.Points[3]);

                Line2d line1 = new Line2d { Start = s1, End = e1 };
                Line2d line2 = new Line2d { Start = s2, End = e2 };

                List<Line2d> rs = new List<Line2d>();
                foreach (Line2d item in this.Curves[0].Curve2ds)
                {

                    if (Line2d.PointInLine(item, window.StartPoint))
                    {
                        rs.Add(item);
                    }
                    if (Line2d.PointInLine(item, window.EndPoint))
                    {
                        rs.Add(item);

                    }
                }
                foreach (var item in rs)
                {
                    this.Curves[0].Curve2ds.Remove(item);
                }
                rs = new List<Line2d>();
                foreach (Line2d item in this.Curves[0].Curve2ds)
                {
                    if (Line2d.PointInLine(item, s1) || Line2d.PointInLine(item, s2) || Line2d.PointInLine(item, e1) || Line2d.PointInLine(item, e2))
                    {
                        rs.Add(item);
                    }
                }
                Dictionary<Line2d, Line2d> dls = new Dictionary<Line2d, Line2d>();
                List<Line2d> cus = new List<Line2d>();
                foreach (Line2d item in rs)
                {
                    foreach (Line2d item2 in rs)
                    {
                        if (item != item2 && Line2d.LineInLine1(item, item2))
                        {
                            if (!cus.Contains(item2) && !cus.Contains(item))
                            {
                                cus.Add(item2); cus.Add(item);
                                dls.Add(item, item2);
                            }
                        }
                    }
                }
                foreach (var item in dls)
                {
                    this.Curves[0].Curve2ds.Remove(item.Key);
                    this.Curves[0].Curve2ds.Remove(item.Value);
                    if (Vector2.Distance(item.Key.Start, item.Value.Start) > Vector2.Distance(item.Key.End, item.Value.Start))
                    {
                        if (Vector2.Distance(item.Key.Start, item.Value.End) > Vector2.Distance(item.Key.Start, item.Value.Start))
                            this.Curves[0].Curve2ds.Add(new Line2d() { Start = item.Key.Start, End = item.Value.End });
                        else
                            this.Curves[0].Curve2ds.Add(new Line2d() { Start = item.Key.Start, End = item.Value.Start });

                    }
                    else
                    {
                        if (Vector2.Distance(item.Key.Start, item.Value.End) > Vector2.Distance(item.Key.Start, item.Value.Start))
                            this.Curves[0].Curve2ds.Add(new Line2d() { Start = item.Key.End, End = item.Value.End });
                        else
                            this.Curves[0].Curve2ds.Add(new Line2d() { Start = item.Key.End, End = item.Value.Start });
                    }
                }
            }

            this.AssociateElements.Remove(associateElement);
        }
        public void UpdateLcComponent(LcElement lcElement, string name, AssociateType type)
        {
            RemoveLcComponent(lcElement, name, type);
            AddLcComponent(lcElement, name, type);

            //AssociateElement associateEl = null;
            //foreach (var item in this.AssociateElements)
            //{
            //    if (item.Element == lcElement && item.Type == type)
            //    {
            //        this.AssociateElements.Remove(item);
            //        break;
            //    }
            //}
            //this.AssociateElements.Add(associateElement);
        }
        private List<QdWall> GetCrossWalls(Line2d line2d)
        {
            var walls = Document.ModelSpace.Elements.Where((ele) => ele.Type == ArchElementType.Wall).ToList();
            List<QdWall> lwalls = new List<QdWall>();
            foreach (QdWall wall in walls)
            {
                if (line2d != wall.BaseLine)
                {
                    if (wall.BaseLine.Start.Similarity(line2d.Start) || wall.BaseLine.Start.Similarity(line2d.End) || wall.BaseLine.End.Similarity(line2d.Start) || wall.BaseLine.End.Similarity(line2d.End))
                    {
                        lwalls.Add(wall);
                    }
                    else
                        if (Line2d.CrossLine(line2d, wall.BaseLine))
                    {
                        lwalls.Add(wall);
                    }
                }
            }
            return lwalls;
        }

        public override LcElement ApplyMatrix(Matrix3 matrix)
        {
            BaseLine.Start = matrix.MultiplyPoint(BaseLine.Start);
            BaseLine.End = matrix.MultiplyPoint(BaseLine.End);
            ResetShapeCurves();
            return this;
        }

        public override LcElement Clone()
        {
            var clone = new QdWall(this.Definition as QdWallDef);
            clone.Copy(this);
            clone.Initilize(this.Document);
            return clone;

        }

        public override void Copy(LcElement src)
        {
            base.Copy(src);
            var wall = ((QdWall)src);
            this.BaseLine = wall.BaseLine.Clone() as Line2d;
        }

        public void Set(Vector2 start = null, Vector2 end = null, bool fireChangedEvent = true)
        {
            //PropertySetter:Start,End
            if (!fireChangedEvent)
            {
                if (start != null) BaseLine.Start = start;
                if (end != null) BaseLine.End = end;
            }
            else
            {
                bool chg_start = (start != null && start != BaseLine.Start);
                bool chg_end = (end != null && end != BaseLine.End);
                if (!chg_start && !chg_end)
                    return;
                var old = BaseLine.Clone();
                OnPropertyChangedBefore(nameof(BaseLine), BaseLine, null);
                if (chg_start)
                {
                    OnPropertyChangedBefore(nameof(BaseLine.Start), BaseLine.Start, start);
                    var oldValue = BaseLine.Start;
                    BaseLine.Start = start;
                }
                if (chg_end)
                {
                    var oldValue = BaseLine.End;
                    BaseLine.End = end;
                }
                this.ResetCache();
                OnPropertyChangedAfter(nameof(BaseLine.Start), old, BaseLine);
            }
        }

        protected override void OnPropertyChanged(string propertyName, LcPropertyGroup extPropGroup, LcProperty extProp)
        {
            base.OnPropertyChanged(propertyName, extPropGroup, extProp);
            ResetShapeCurves();
        }
        public override Box2 GetBoundingBox()
        {
            return new Box2().SetFromPoints(BaseLine.Start, BaseLine.End);
        }
        public override Box2 GetBoundingBox(Matrix3 matrix)
        {
            return new Box2().SetFromPoints(matrix.MultiplyPoint(BaseLine.Start), matrix.MultiplyPoint(BaseLine.End));
        }
        public override bool IntersectWithBox(Polygon2d testPoly, List<RefChildElement> intersectChildren = null)
        {
            var thisBox = this.BoundingBox;
            if (!thisBox.IntersectsBox(testPoly.BoundingBox))
            {
                //如果元素盒子，与多边形盒子不相交，那就可能不相交
                return false;
            }
            return GeoUtils.IsPolygonIntersectLine(testPoly.Points, BaseLine.Start, BaseLine.End)
                || GeoUtils.IsPolygonContainsLine(testPoly.Points, BaseLine.Start, BaseLine.End);
        }

        public override bool IncludedByBox(Polygon2d testPoly, List<RefChildElement> includedChildren = null)
        {
            var thisBox = this.BoundingBox;
            if (!thisBox.IntersectsBox(testPoly.BoundingBox))
            {
                return false;
            }
            return GeoUtils.IsPolygonContainsLine(testPoly.Points, BaseLine.Start, BaseLine.End);
        }

        public override void Translate(double dx, double dy)
        {
            var ts = new Vector2(BaseLine.Start.X + dx, BaseLine.Start.Y + dy);
            var te = new Vector2(BaseLine.End.X + dx, BaseLine.End.Y + dy);
            Set(ts, te);
            ResetBoundingBox();
            ResetShapeCurves();

        }
        public override void Move(Vector2 startPoint, Vector2 endPoint)
        {
            Matrix3 matrix3 = Matrix3.GetMove(startPoint, endPoint);
            this.Set(matrix3.MultiplyPoint(BaseLine.Start), matrix3.MultiplyPoint(BaseLine.End));
            ResetBoundingBox();
            ResetShapeCurves();
        }
        public override void Scale(Vector2 basePoint, double scaleFactor)
        {
            Matrix3 matrix3 = Matrix3.GetScale(scaleFactor, basePoint);
            this.Set(matrix3.MultiplyPoint(BaseLine.Start), matrix3.MultiplyPoint(BaseLine.End));
            ResetBoundingBox();
            ResetShapeCurves();
        }
        public override void Scale(Vector2 basePoint, Vector2 scaleVector)
        {

            Matrix3 matrix3 = Matrix3.GetScale(scaleVector, basePoint);
            this.Set(matrix3.MultiplyPoint(BaseLine.Start), matrix3.MultiplyPoint(BaseLine.End));
            ResetBoundingBox();
            ResetShapeCurves();
        }
        public override void Rotate(Vector2 basePoint, double rotateAngle)
        {
            Matrix3 matrix3 = Matrix3.RotateInRadian(rotateAngle, basePoint);
            this.Set(matrix3.MultiplyPoint(BaseLine.Start), matrix3.MultiplyPoint(BaseLine.End));
            ResetBoundingBox();
            ResetShapeCurves();
        }
        public override void Mirror(Vector2 axisStart, Vector2 axisEnd)
        {
            Matrix3 matrix3 = Matrix3.GetMirror(axisEnd, axisStart);
            this.Set(matrix3.MultiplyPoint(BaseLine.Start), matrix3.MultiplyPoint(BaseLine.End));
            ResetBoundingBox();
            ResetShapeCurves();
        }
        public override void ResetCache()
        {
            base.ResetCache();
            this.ResetShapeCurves();
        }
        public override void WriteProperties(Utf8JsonWriter writer, JsonSerializerOptions soptions)
        {
            base.WriteProperties(writer, soptions);
        }
        public override void ReadProperties(ref JsonElement jele)
        {
            base.ReadProperties(ref jele);

            this.BaseLine = jele.ReadCurve2dProperty(nameof(this.BaseCurve)) as Line2d;
            this.CreateShapeCurves();
        }
    }
}